(function(){
var dh = $$.DomHelper
	,wrapCls = 'cf-el-wrap'
	,mapSide = {t: 'Top' ,r: 'Right' ,b: 'Bottom' ,l: 'Left'}
	,mapOffset = {p: 'Padding', b: 'BorderWidth', m: 'Margin'};
	
$$.Element = $$.Class($$.Component, {
	draggable: false
	,constructor: function(el, config){
		$$.put(this, config);
		
		if($$.isString(el)) el = document.querySelector(el);
		else if(! el || $$.isObject(el)) el = dh.create(el);
		this.dom = el;
		
		this.addEvents(
			'click'
			,'dbclick'
			,'keydown'
			,'keypress'
			,'keyup'
			,'mousedown'
			,'mousemove'
			,'mouseout'
			,'mouseover'
			,'mouseup'
			,'mouseenter'
		);
		
		var me = this;
		
		this.dom.onclick = function(e){
			me.fireEvent('click', me, e);
		};
		this.dom.ondbclick = function(e){
			me.fireEvent('dbclick', me, e);
		};
		this.dom.onkeydown = function(e){
			me.fireEvent('keydown', me, e);
		};
		this.dom.onkeypress = function(e){
			me.fireEvent('keypress', me, e);
		};
		this.dom.onkeyup = function(e){
			me.fireEvent('keyup', me, e);
		};
		this.dom.onmousedown = function(e){
			me.fireEvent('mousedown', me, e);
		};
		this.dom.onmousemove = function(e){
			me.fireEvent('mousemove', me, e);
		};
		this.dom.onmouseout = function(e){
			me.fireEvent('mouseout', me, e);
		};
		this.dom.onmouseover = function(e){
			me.fireEvent('mouseover', me, e);
		};
		this.dom.onmouseup = function(e){
			me.fireEvent('mouseup', me, e);
		};
		this.dom.onmouseenter = function(e){
			me.fireEvent('mouseenter', me, e);
		};
		
		this.__parent.constructor.call(this, config);
		this.initDD();
	}
	,initDD: function(){
		if(!this.draggable) return;
		this.getDD();
	}
	,getDD: function(){
		if(this.____dd) return this.____dd;
		this.____dd = new $$.dd.DragDrop(this, this.draggable);
		return this.____dd;
	}
	,appendChild: function(/*arguments*/){
		for(var i = 0; i < arguments.length; ++i)
		dh.append(this.dom, arguments[i]);
		return this;
	}
	,insertAt: function(index, children, returnEl){
		var dom = dh.insertAt(this.dom, index, children);
		return returnEl? new $$.Element(dom) : dom;
	}
	,removeAt: function(/* args */){
		for(var i = 0; i < arguments.length; ++i){
			this.dom.removeChild(this.dom.children.item(i));
		}
		return this;
	}
	,appendTo: function(el){
		var dom = $$.getDom(el);
		dh.append(dom, this.dom);
		return this;
	}
	,getAt: function(index){
		return this.dom.children.item(index);
	}
	,select: function(selector){
		return this.dom.querySelector(selector);	
	}
	,selectAll: function(selector){
		return this.dom.querySelectorAll(selector);
	}
	,first: function(){
		return this.dom.firstElementChild;	
	}
	,last: function(){
		return this.dom.lastElementChild;	
	}
	,addClass: function(cls){
		dh.addClass(this.dom, cls);
		return this;
	}
	,removeClass: function(cls){
		dh.removeClass(this.dom, cls);
	}
	,getStyle: function(prop){
		var dom = this.dom;
		if(dom == document) return null;
		
		var v;
		if(v = dom.style[prop]) return v;
		
		var view = document.defaultView;
		if(view && view.getComputedStyle){
			if(v = getComputedStyle(dom, null)) return v[prop];
			return null;
		}
		
		if(v = dom.currentStyle) return v[prop];
		return null;
	}
	,setStyle: function(style, value){
		dh.setStyle(this.dom, style, value);
		return this;
	}
	,setVisible: function(visible){
		if(true === visible) visible = 'visible';
		if(false === visible) visible = 'hidden';
		this.dom.style.visibility = visible;
		return this;
	}
	,setDisplay: function(display){
		if(true === display) display = 'auto';
		if(false === display) display = 'none';
		this.dom.style.display = display;
		return this;
	}
	,hide: function(){
		this.setVisible(false);
		return this;
	}
	,show: function(){
		this.setVisible(true);
		return this;
	}
	,wrap: function(o, returnDom){
		var dom = dh.wrap(this.dom, o);
		return returnDom? dom : new $$.Element(dom);
	}
	,unWrap: function(){
		dh.unWrap(this.dom);
		return this;
	}
	,update: function(o){
		dh.update(this.dom, o);
		return this;
	}
	,getPadding: function(side){
		var ret = 0, s;
			
		for(var i = 0; i < side.length; ++i){
			ret += (s = this.getStyle('padding' + mapSide[side[i]]).match(/\d+/))? parseInt(s[0]) : 0;
		}

		return ret;
	}
	,getBorderWidth: function(side){
		var ret = 0 ,s;
			
		for(var i = 0; i < side.length; ++i){
			ret += (s = this.getStyle('border' + mapSide[side[i]] + 'Width').match(/\d+/))? parseInt(s[0]) : 0;
		}

		return ret;
	}
	,getMargin: function(side){
		var ret = 0, s;
			
		for(var i = 0; i < side.length; ++i){
			ret += (s = this.getStyle('margin' + mapSide[side[i]]).match(/\d+/))? parseInt(s[0]) : 0;
		}

		return ret;
	}
	,getWidth: function(offset){
		var w = this.getStyle('width').match(/\d+/);
		w = w? parseInt(w[0]) : 0;
		if(!offset) return w;
		
		for(var i = 0; i < offset.length; ++i){
			w += this['get' + mapOffset[offset[i]]]('lr');
		}
		return w;
	}
	,getHeight: function(offset){
		var h = this.getStyle('height').match(/\d+/);
		h = h? parseInt(h[0]) : 0;
		if(!offset) return h;
		
		for(var i = 0; i < offset.length; ++i){
			h += this['get' + mapOffset[offset[i]]]('tb');
		}
		return h;
	}
	,getSize: function(offset){
		return this.getWidth() + this.getHeight();
	}
	,setWidth: function(w, offset){
		if($$.isNumber(w)){
			if(offset){
				for(var i = 0; i < offset.length; ++i){
					w -= this['get' + mapOffset[offset[i]]]('lr');
				}
			}
			if(w < 0) w = 0;
			w = w + 'px';
		}
		return this.setStyle({width: w});
	}
	,setHeight: function(h, offset){
		if($$.isNumber(h)){
			if(offset){
				for(var i = 0; i < offset.length; ++i){
					h -= this['get' + mapOffset[offset[i]]]('tb');
				}
			}
			if(h < 0) h = 0;
			h = h + 'px';
		}
		return this.setStyle({height: h});
	}
	,setSize: function(w, h, offset){
		return this.setWidth(w, offset).setHeight(h, offset);
	}
	/*,getX: function(){
		var l = this.getStyle('left').match(/\d+/);
		return l? l[0] : 0;
	}
	,getY: function(){
		var r = this.getStyle('top').match(/\d+/);
		return r? r[0] : 0;
	}
	,getXY: function(){
		return [this.getX(), this.getY()];
	}*/
	,setX: function(x){
		x = typeof x == 'number'? x + 'px' : x;
		return this.setStyle({left: x});
	}
	,setY: function(y){
		y = typeof y == 'number'? y + 'px' : y;
		return this.setStyle({top: y});
	}
	,setXY: function(x, y){
		if(!y) y = x;
		return this.setX(x).setY(y);
	}
	,getX: function(){
		return this.dom.offsetLeft;
	}
	,getY: function(){
		return this.dom.offsetTop;
	}
	,getXY: function(){
		return [this.getX(), this.getY()];
	}
	,replace: function(o){
		dh.replace(this.dom, o);
		return this;
	}
	,replaceWith: function(o){
		dh.replace(o, this.dom);
		return this;	
	}
	,destroy: function(){
		dh.remove(this.dom);	
	}
	,toHTML: function(){
		var html = this.wrap({}, true).innerHTML;
		this.unWrap();
		return html;
	}
});
})();